package com.yh.csx.crm.webapi.controller;

import com.yh.csx.crm.appapi.controller.BaseController;
import com.yh.csx.crm.core.entity.CommonResponse;
import com.yh.csx.crm.core.enums.PermissionTypeEnum;
import com.yh.csx.crm.core.enums.PositionEnum;
import com.yh.csx.crm.core.exception.BusinessException;
import com.yh.csx.crm.core.model.PageList;
import com.yh.csx.crm.core.util.BeanUtils;
import com.yh.csx.crm.core.util.DownloadUtils;
import com.yh.csx.crm.core.util.ExcelUtils;
import com.yh.csx.crm.po.SysOrganization;
import com.yh.csx.crm.po.SysSalesPermission;
import com.yh.csx.crm.qo.OrganizationQo;
import com.yh.csx.crm.qo.SalesQo;
import com.yh.csx.crm.service.OrganizationService;
import com.yh.csx.crm.service.SaleService;
import com.yh.csx.crm.service.request.SalesReq;
import com.yh.csx.crm.service.request.SalesSearchReq;
import com.yh.csx.crm.service.response.SalesResp;
import com.yh.csx.crm.vo.SalesImportVo;
import com.yh.csx.crm.vo.SalesInfoVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Huang Zhaoping
 * @date 2019/4/11
 */
@Api("用户管理")
@RestController
@RequestMapping("/sales")
public class SalesController extends BaseController {

    @Autowired
    private SaleService saleService;

    @Autowired
    private OrganizationService organizationService;

    @ApiOperation("查找用户列表")
    @GetMapping("/list")
    public CommonResponse<PageList<SalesResp>> findSalesList(SalesSearchReq req) {
        return visit(() -> {
            SalesQo qo = BeanUtils.convert(SalesQo.class, req);
            List<SalesInfoVo> list = saleService.findSalesList(qo);
            return PageList.of(list, vo -> {
                SalesResp resp = BeanUtils.convert(SalesResp.class, vo);
                resp.setPositionName(PositionEnum.resolveName(vo.getPosition()));
                resp.setPermissionTypeName(PermissionTypeEnum.resolveName(vo.getPermissionType()));
                if (StringUtils.isNotBlank(vo.getRelatedOrgs())) {
                    resp.setOrgList(Stream.of(vo.getRelatedOrgs().split(",")).map(Integer::valueOf).collect(Collectors.toList()));
                }
                return resp;
            });
        });
    }

    @ApiOperation("新增用户")
    @PostMapping("/create")
    public CommonResponse<Void> createSales(@RequestBody SalesReq req) {
        return visit(() -> {
            SysSalesPermission sales = BeanUtils.convert(SysSalesPermission.class, req);
            if (CollectionUtils.isNotEmpty(req.getOrgList())) {
                sales.setRelatedOrgs(StringUtils.join(req.getOrgList(), ","));
            }
            sales.setCreateBy(getUserName());
            sales.setUpdateBy(sales.getCreateBy());
            saleService.createSales(sales);
        });
    }

    @ApiOperation("修改用户信息")
    @PostMapping("/update/{id}")
    public CommonResponse<Void> updateSales(@PathVariable Integer id, @RequestBody SalesReq req) {
        return visit(() -> {
            SysSalesPermission sales = BeanUtils.convert(SysSalesPermission.class, req);
            if (CollectionUtils.isNotEmpty(req.getOrgList())) {
                sales.setRelatedOrgs(StringUtils.join(req.getOrgList(), ","));
            }
            sales.setId(id);
            sales.setUpdateBy(getUserName());
            saleService.updateSales(sales);
        });
    }

    @ApiOperation("删除用户")
    @PostMapping("/delete/{id}")
    public CommonResponse<Void> deleteSales(@PathVariable Integer id) {
        return visit(() -> saleService.deleteSales(id));
    }

    @ApiOperation("获取导入模板")
    @GetMapping("/template")
    public void getTemplate(HttpServletRequest request, HttpServletResponse response) {
        visit(() -> DownloadUtils.download(request, response, "templates/user_import.xlsx"));
    }

    @ApiOperation("批量导入用户")
    @PostMapping("/import")
    public CommonResponse<Void> importSales(MultipartFile file) {
        return visit(() -> {
            List<SalesImportVo> list;
            try {
                list = ExcelUtils.readObjectList(file.getInputStream(), 1, 1, SalesImportVo.class);
            } catch (IOException e) {
                throw new BusinessException("读取导入文件异常", e);
            }
            if (list.isEmpty()) throw new BusinessException("导入用户为空");
            Set<String> phoneSet = new HashSet<>();
            Map<String, SysSalesPermission> workNumberMap = new HashMap<>();
            List<SysOrganization> orgList = organizationService.findOrganizationList(new OrganizationQo());
            Map<String, List<SysOrganization>> orgMap = orgList.stream().collect(Collectors.groupingBy(o -> o.getDepartment()));
            String importUser = getUserName();
            List<SysSalesPermission> salesList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
                SalesImportVo vo = list.get(i);
                SysSalesPermission sales = new SysSalesPermission();
                // 数据校验
                if (StringUtils.isBlank(vo.getWorkNumber())) throwRowError(i, "工号不能为空");
                if (workNumberMap.put(vo.getWorkNumber(), sales) != null) throwRowError(i, "工号重复");
                if (saleService.findSalesByWorkNumber(vo.getWorkNumber()) != null) throwRowError(i, "工号已经存在");
                if (StringUtils.isBlank(vo.getUserName())) throwRowError(i, "用户姓名不能为空");
                if (StringUtils.isBlank(vo.getPhone())) throwRowError(i, "手机号码不能为空");
                if (!phoneSet.add(vo.getPhone())) throwRowError(i, "手机号码重复");
                if (saleService.findSalesPermission(vo.getPhone()) != null) throwRowError(i, "手机号码已经注册");
                if (PositionEnum.resolve(vo.getPosition()) == null) throwRowError(i, "职位编码无效");
                if (StringUtils.isBlank(vo.getOrgName())) throwRowError(i, "所属部门不能为空");
                if (StringUtils.isBlank(vo.getPermissionType())) throwRowError(i, "数据权限不能为空");
                if (!StringUtils.isNumeric(vo.getPermissionType())) throwRowError(i, "数据权限类型无效");
                if (!StringUtils.isNumeric(vo.getPermissionType())
                        || PermissionTypeEnum.resolve(Integer.valueOf(vo.getPermissionType())) == null) throwRowError(i, "数据权限类型无效");
                // 设置数据
                sales.setWorkNumber(vo.getWorkNumber());
                sales.setUserName(vo.getUserName());
                sales.setPhone(vo.getPhone());
                sales.setPosition(vo.getPosition());
                sales.setOrgId(findOrganization(orgMap, i, vo.getOrgName()).getId());
                if (orgList.stream().filter(o -> Objects.equals(o.getParentId(), sales.getOrgId())).findAny().isPresent()) {
                    throwRowError(i, "部门[" + vo.getOrgName() + "]包含下级部门");
                }
                sales.setPermissionType(Integer.valueOf(vo.getPermissionType()));
                if (StringUtils.isNotBlank(vo.getOrgNameList())) {
                    String[] orgNames = vo.getOrgNameList().split(",");
                    List<SysOrganization> orgs = new ArrayList<>();
                    for (String orgName : orgNames) {
                        orgs.add(findOrganization(orgMap, i, orgName));
                    }
                    sales.setRelatedOrgs(StringUtils.join(orgs.stream().map(SysOrganization::getId).collect(Collectors.toList()), ","));
                }
                // 临时存储下上级工号
                sales.setPath(vo.getManagerWorkNumber());
                sales.setCreateBy(importUser);
                sales.setUpdateBy(importUser);
                salesList.add(sales);
            }
            // 检查是否存在循环依赖
            for (int i = 0; i < salesList.size(); i++) {
                SysSalesPermission sales = salesList.get(i);
                if (StringUtils.isBlank(sales.getPath())) continue;
                SysSalesPermission parent = workNumberMap.get(sales.getPath());
                if (parent == null) {
                    parent = saleService.findSalesByWorkNumber(sales.getPath());
                    if (parent == null) throwRowError(i, "所属领导不存在");
                    sales.setParid(parent.getUserId());
                }
                Set<String> dependSet = new HashSet<>();
                dependSet.add(sales.getWorkNumber());
                while (parent != null && StringUtils.isNotBlank(parent.getPath())) {
                    if (!dependSet.add(parent.getWorkNumber())) throwRowError(i, "存在所属领导循环依赖问题");
                    parent = workNumberMap.get(parent.getPath());
                }
            }
            // 根据依赖顺序插入用户
            Set<String> createdSet = new HashSet<>();
            for (SysSalesPermission sales : salesList) {
                if (StringUtils.isBlank(sales.getPath()) || sales.getParid() != null) {
                    if (createdSet.add(sales.getWorkNumber())) {
                        saleService.createSales(sales);
                    }
                } else {
                    List<SysSalesPermission> dependList = new ArrayList<>();
                    dependList.add(sales);
                    SysSalesPermission parent = workNumberMap.get(sales.getPath());
                    while (parent != null) {
                        dependList.add(parent);
                        if (StringUtils.isNotBlank(parent.getPath())) {
                            parent = workNumberMap.get(parent.getPath());
                        } else {
                            parent = null;
                        }
                    }
                    for (int i = dependList.size() - 1; i >= 0; i--) {
                        SysSalesPermission depend = dependList.get(i);
                        if (parent != null) depend.setParid(parent.getUserId());
                        if (createdSet.add(depend.getWorkNumber())) {
                            saleService.createSales(depend);
                        }
                        parent = depend;
                    }
                }
            }
        });
    }

    private void throwRowError(int index, String message) {
        throw new BusinessException("第[" + (index + 2) + "]行：" + message);
    }

    private SysOrganization findOrganization(Map<String, List<SysOrganization>> orgMap, int index, String name) {
        List<SysOrganization> list = orgMap.get(name);
        if (list == null) {
            String[] values = name.split("->");
            if (values.length <= 1) throwRowError(index, "部门[" + name + "]不存在");
            final Set<Integer> parentIds = new HashSet<>();
            for (int i = 0; i < values.length; i++) {
                String value = values[i];
                list = orgMap.get(value);
                if (list == null) throwRowError(index, "部门[" + value + "]不存在");
                if (parentIds.size() > 0) {
                    list = list.stream().filter(o -> parentIds.contains(o.getParentId())).collect(Collectors.toList());
                }
                if (list.size() == 0) {
                    throwRowError(index, "部门[" + name + "]不存在");
                }
                parentIds.clear();
                list.forEach(o -> parentIds.add(o.getId()));
            }
            if (list.size() != 1) {
                throwRowError(index, "部门[" + name + "]重复，请使用 上级名称->部门名称 的方式来指定");
            }
        } else if (list.size() > 1) {
            throwRowError(index, "部门[" + name + "]重复，请使用 上级名称->部门名称 的方式来指定");
        }
        return list.get(0);
    }

}
